﻿// Decompiled with JetBrains decompiler
// Type: Netick.NetworkStack`1
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System;
using System.Collections;
using System.Collections.Generic;

#nullable disable
namespace Netick;

/// <summary>
/// A networked <see cref="T:System.Collections.Generic.Stack`1" /> collection.
/// </summary>
public sealed class NetworkStack<T> : NetworkStack, INetworkCollection, IEnumerable<T>, IEnumerable where T : unmanaged
{
  private Stack<T> _original;

  public NetworkStack(int capacity)
  {
    this._length = capacity;
    this._original = new Stack<T>(capacity);
  }

  public override unsafe void InternalInit(
    INetickNetworkScript beh,
    int* state,
    int elementSizeWords,
    int flags)
  {
    base.InternalInit(beh, state, elementSizeWords, flags);
    this._elementSizeWords = NetickUtils.GetWordSize(sizeof (T));
  }

  public IEnumerator<T> GetEnumerator()
  {
    int count = this.Count;
    for (int i = 0; i < count; ++i)
      yield return this.GetElementDataPtr(count - 1 - i);
  }

  IEnumerator IEnumerable.GetEnumerator() => (IEnumerator) this.GetEnumerator();

  internal unsafe void SetElementData(int index, T value)
  {
    this._entity.SetState_Collection((int*) &value, this._intS + 1 + index * this._elementSizeWords, this._elementSizeWords, 0, (this._flags & NetworkCollectionMeta.IsInputSourceOnly) == NetworkCollectionMeta.IsInputSourceOnly ? 1 : 0, (this._flags & NetworkCollectionMeta.HasOnChanged) == NetworkCollectionMeta.HasOnChanged ? 1 : 0);
  }

  internal unsafe T GetElementDataPtr(int index)
  {
    return *(T*) (this._intS + 1 + index * this._elementSizeWords);
  }

  /// <summary>Gets the number of items contained in the stack.</summary>
  public unsafe int Count
  {
    get => (IntPtr) this._intS == IntPtr.Zero ? this._original.Count : *this._intS;
    internal set
    {
      this._entity.SetState_Collection(&value, this._intS, 1, (this._flags & NetworkCollectionMeta.HasOnChanged) == NetworkCollectionMeta.HasOnChanged ? 1 : 0, (this._flags & NetworkCollectionMeta.IsInputSourceOnly) == NetworkCollectionMeta.IsInputSourceOnly ? 1 : 0, (this._flags & NetworkCollectionMeta.HasOnChanged) == NetworkCollectionMeta.HasOnChanged ? 1 : 0);
    }
  }

  /// <summary>Removes all items from the stack.</summary>
  public void Clear() => this.Count = 0;

  /// <summary>Pushes an item onto the top of the stack.</summary>
  /// <param name="item">The item to push onto the stack.</param>
  /// <returns>True if the item was pushed; false if the stack is full.</returns>
  public bool Push(T item)
  {
    int count = this.Count;
    if (count >= this._length)
      return false;
    this.SetElementData(count, item);
    ++this.Count;
    return true;
  }

  /// <summary>Removes and returns the item at the top of the stack.</summary>
  /// <returns>The item removed from the top of the stack, or default if the stack is empty.</returns>
  public T Pop()
  {
    int count = this.Count;
    if (count <= 0)
      return default (T);
    this.Count = count - 1;
    return this.GetElementDataPtr(count - 1);
  }

  /// <summary>
  /// Attempts to remove and return the item at the top of the stack.
  /// </summary>
  /// <param name="result">The item removed from the top of the stack, or default if the stack is empty.</param>
  /// <returns>True if an item was removed; otherwise, false.</returns>
  public bool TryPop(out T result)
  {
    int count = this.Count;
    if (count > 0)
    {
      this.Count = count - 1;
      result = this.GetElementDataPtr(count - 1);
      return true;
    }
    result = default (T);
    return false;
  }

  /// <summary>
  /// Returns the item at the top of the stack without removing it.
  /// </summary>
  /// <returns>The item at the top of the stack, or default if the stack is empty.</returns>
  public T Peek()
  {
    int count = this.Count;
    return count <= 0 ? default (T) : this.GetElementDataPtr(count - 1);
  }

  /// <summary>
  /// Attempts to return the item at the top of the stack without removing it.
  /// </summary>
  /// <param name="result">The item at the top of the stack, or default if the stack is empty.</param>
  /// <returns>True if an item was returned; otherwise, false.</returns>
  public bool TryPeek(out T result)
  {
    int count = this.Count;
    if (count > 0)
    {
      result = this.GetElementDataPtr(count - 1);
      return true;
    }
    result = default (T);
    return false;
  }

  /// <summary>
  /// Adds an item to the original stack (used for internal state).
  /// </summary>
  /// <param name="item">The element to add.</param>
  public void Add(T item) => this._original.Push(item);

  public override void InternalReset()
  {
    for (int index = 0; index < this._length; ++index)
      this.SetElementData(index, default (T));
    int index1 = 0;
    foreach (T obj in this._original)
    {
      this.SetElementData(index1, obj);
      ++index1;
    }
    this.Count = this._original.Count;
  }
}
